Better control of marks through conditional and for expressions #710
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The unknown value paths within conditional and for expressions were not consistently retaining marks.
In the case of for expressions, an unknown collection would lose all marks. If we have the any marks from the collection we can always return those. If the expression contains a conditional include, we can also attempt to obtain the marks from that since the conditional impacts the total collection value, the marks must alway be included in the final result. This gives us a more complete unknown value, but it can never contain a comprehensive set of marks for all cases. If the collection is entirely unknown, we have no idea what the element value marks are going to be, so the final known result could still always include marks we were not anticipating.
The conditional expressions are more straightforward to fix, but also more troublesome from Terraform's perspective because it represents a change in behavior. Previously, the marks for the true and false values were kept distinct and were not included at all if the result was unknown. This poses a problem when behavior is specified by marks on the values, because the behavior changes depending on whether the result is known or not. The only way to reconcile this with conditionals is to always combine all marks, which is what I've done here. The union of marks definitely makes logical sense when the condition is unknown, since we could have either set, but could be surprising for configurations which could never produce an unknown condition.
The change in marks looks like so (using letters for variables and numbers for marks):
x(1) ? y(2) : z(3)
x
Unknownx
Truex
False<unknown>()
y(2)
z(3)
<unknown>(1,2,3)
y(1,2,3)
z(1,2,3)
You can see here that if
1
represented "sensitive" as used in Terraform, the result which is derived from a sensitive value had no indication of that. A case could be made that the y and z values should bey(1,2)
andz(1,3)
, but conditional expressions already need to unify the return type, so it feels natural that it should also unify the meta-type information like marks, making the results more consistent and predictable.